﻿/******************************************************************************
* SunnyUI.FrameDecoder 开源TCP、串口数据解码库。
* CopyRight (C) 2022-2023 ShenYongHua(沈永华).
* QQ群：56829229 QQ：17612584 EMail：SunnyUI@qq.com
*
* Blog:   https://www.cnblogs.com/yhuse
* Gitee:  https://gitee.com/yhuse/SunnyUI.FrameDecoder
*
* SunnyUI.FrameDecoder.dll can be used for free under the MIT license.
* If you use this code, please keep this note.
* 如果您使用此代码，请保留此说明。
******************************************************************************
* 文件名称: NMEA0183FrameDecoder.cs
* 文件说明: NMEA0183 - 数据帧解码器
* 当前版本: V1.0
* 创建日期: 2022-11-01
*
* 2022-11-01: V1.0.0 增加文件说明
* 2023-07-15: V4.4.0 AIS数据增加了一个前缀“！”
******************************************************************************/

using System;

namespace Sunny.FrameDecoder
{
    /// <summary>
    /// NMEA0183 - 数据帧解码器
    /// </summary>
    public class NMEA0183FrameDecoder : BaseStringFrameDecoder
    {
        private const string StartChar1 = "$";
        private const string StartChar2 = "!";
        private const string EndChar = "*";

        /// <summary>
        /// 解码函数
        /// </summary>
        protected override void Decoding()
        {
            int idx11 = Cache.WrittenSpan.IndexOf(StartChar1.AsSpan());
            int idx12 = Cache.WrittenSpan.IndexOf(StartChar2.AsSpan());

            if (idx11 < 0 && idx12 < 0) return;
            if (idx11 >= 0 && idx12 < 0) Cache.Remove(idx11);
            if (idx12 >= 0 && idx11 < 0) Cache.Remove(idx12);
            if (idx11 >= 0 && idx12 >= 0) Cache.Remove(Math.Min(idx11, idx12));

            int idx2 = Cache.WrittenSpan.Slice(1).IndexOf(EndChar.AsSpan());
            while (idx2 >= 0)
            {
                if (Cache.WrittenCount < idx2 + 1 + 1 + 2)
                    break;

                LastDecodedTime = DateTime.Now;
                StringFrameEventArgs e = new(this, Cache.WrittenSpan.Slice(0, idx2 + 4).ToString());
                InvokeOnDecoder(e);

                Cache.Remove(idx2 + 2);

                idx11 = Cache.WrittenSpan.IndexOf(StartChar1.AsSpan());
                idx12 = Cache.WrittenSpan.IndexOf(StartChar2.AsSpan());

                if (idx11 < 0 && idx12 < 0) break;
                if (idx11 >= 0 && idx12 < 0) Cache.Remove(idx11);
                if (idx12 >= 0 && idx11 < 0) Cache.Remove(idx12);
                if (idx11 >= 0 && idx12 >= 0) Cache.Remove(Math.Min(idx11, idx12));

                idx2 = Cache.WrittenSpan.Slice(1).IndexOf(EndChar.AsSpan());
            }
        }

        /// <summary>
        /// 准备数据解码
        /// </summary>
        /// <param name="data">输入数据</param>
        /// <returns>判断此数据是否可以解码</returns>
        protected override bool PrepareDecode(ref string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                InvokeDecoderError("The data to be decoded is null.", data);
                return false;
            }

            return Cache.WrittenCount != 0 || (data.AsSpan().IndexOf(StartChar1.AsSpan()) >= 0 || data.AsSpan().IndexOf(StartChar2.AsSpan()) >= 0);
        }
    }
}
